home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Tools / Languages / MacHaskell 2.2 / type / unify.scm < prev   
Encoding:
Text File  |  1994-09-27  |  5.4 KB  |  155 lines  |  [TEXT/CCL2]

  1.  
  2. ;;; File: type/unify.scm   Author: John
  3.  
  4. ;;; This is the basic unification algorithm used in type checking.
  5.  
  6. ;;; Unification failure invokes the current type error handler
  7.  
  8. ;;; Start by removing instantiated type variables from the type.
  9.  
  10. (define (unify type1 type2)
  11.   (unify-1 (prune type1) (prune type2)))
  12.  
  13. ;;; The only real tweak here is the read-only bit on type variables.
  14. ;;; The rule is that a RO tyvar can be unified only with a generic
  15. ;;; non-RO tyvar which has the same or more general context.
  16.  
  17. ;;; Aside from this, this is standard unification except that context
  18. ;;; propagation is needed when a tyvar with a non-empty context is
  19. ;;; instantiated.
  20.  
  21. ;;; If type2 is a tyvar and type1 is not they are switched.
  22.  
  23. (define (unify-1 type1 type2)
  24.     (cond ((eq? type1 type2)  ;; this catches variable to variable unify
  25.        'OK)
  26.       ((ntyvar? type1)
  27.        (cond ((occurs-in-type type1 type2)
  28.           (type-error "Circular type: cannot unify ~A with ~A"
  29.                   type1 type2))
  30.          ((ntyvar-read-only? type1)
  31.           (cond ((or (not (ntyvar? type2)) (ntyvar-read-only? type2))
  32.              (type-error
  33.               "Signature too general: cannot unify ~A with ~A"
  34.               type1 type2))
  35.             (else
  36.              (unify-1 type2 type1))))
  37.          ((and (ntyvar? type2)
  38.                (ntyvar-read-only? type2)
  39.                (non-generic? type1))
  40.           (type-error
  41.  "Type signature cannot be used: monomorphic type variables present."))
  42.          (else
  43.           (instantiate-tyvar type1 type2)
  44.           (let ((classes (ntyvar-context type1)))
  45.             (if (null? classes)
  46.             'OK
  47.             (propagate-contexts/ntype type1 type2 classes))))))
  48.       ((ntyvar? type2)
  49.        (unify-1 type2 type1))
  50.       ((eq? (forward-def (ntycon-tycon type1))
  51.         (forward-def (ntycon-tycon type2)))
  52.        (unify-list (ntycon-args type1) (ntycon-args type2)))
  53.       (else
  54.        (let ((etype1 (expand-ntype-synonym type1))
  55.          (etype2 (expand-ntype-synonym type2)))
  56.          ;; same-tycon? is part of util/interface-check
  57.         (if (same-tycon? (ntycon-tycon etype1) (ntycon-tycon etype2))
  58.         (unify-list (ntycon-args etype1) (ntycon-args etype2))
  59.         ;; This error message should probably show both the original
  60.         ;; and the expanded types for clarity.
  61.         (type-error
  62.               "Type conflict: type ~A does not match ~A"
  63.                 etype1 etype2))))))
  64.  
  65.  
  66. (define-integrable (instantiate-tyvar tyvar val)
  67.   (setf (ntyvar-value tyvar) val))
  68.  
  69. ;;; unifies two lists of types pairwise.  Used for tycon args.
  70.  
  71. (define (unify-list args1 args2)
  72.   (if (null? args1)
  73.       'OK
  74.       (begin (unify-list (cdr args1) (cdr args2))
  75.          (unify (car args1) (car args2)))))
  76.  
  77. ;;; combines a list of types into a single type.  Used in constructs
  78. ;;; such as [x,y,z] and case expressions.
  79.  
  80. (define (unify-list/single-type types)
  81.   (when (not (null? types))
  82.     (let ((type (car types)))
  83.       (dolist (type2 (cdr types))
  84.         (unify type type2)))))
  85.  
  86. ;;; This propagates the context from a just instantiated tyvar to the
  87. ;;; instantiated value.  If the value is a tycon, instances must be
  88. ;;; looked up.  If the value is a tyvar, the context is added to that of
  89. ;;; other tyvar.
  90.  
  91. ;;; This is used to back out of the unification on errors.  This is a
  92. ;;; poor mans trail stack!  Without this, error messages get very
  93. ;;; obscure.
  94.  
  95. (define *instantiated-tyvar* '())
  96.  
  97. (define (propagate-contexts/ntype tyvar type classes)
  98.  (dynamic-let ((*instantiated-tyvar* tyvar))
  99.     (propagate-contexts/inner type classes)))
  100.  
  101. (define (propagate-contexts/inner type classes)
  102.  (let ((type (prune type)))
  103.   (if (ntyvar? type)
  104.       (if (ntyvar-read-only? type)
  105.       (if (context-implies? (ntyvar-context type) (remove-dynamic classes))
  106.           'OK ; no need for context propagation here
  107.           (begin 
  108.         (setf (ntyvar-value (dynamic *instantiated-tyvar*)) '#f)
  109.         (type-error "Signature context is too general")))
  110.       (if (null? (ntyvar-context type))
  111.           (setf (ntyvar-context type) classes)
  112.           (setf (ntyvar-context type)
  113.             (merge-contexts classes (ntyvar-context type)))))
  114.       (propagate-contexts-1 (expand-ntype-synonym type) classes))))
  115.  
  116. ;;; The type has now been expanded.  This propagates each class constraint
  117. ;;; in turn.
  118.  
  119. (define (propagate-contexts-1 type classes)
  120.   (dolist (class classes)
  121.      (propagate-single-class type class)))
  122.  
  123. ;;; Now we have a single class & data type.  Either an instance decl can
  124. ;;; be found or a type error should be signalled.  Once the instance
  125. ;;; decl is found, contexts are propagated to the component types.
  126.  
  127. (define (propagate-single-class type class)
  128.  (if (eq? class (core-symbol "DynamicType"))
  129.   (propagate-dynamic-class type)
  130.   (let ((instance (lookup-instance (ntycon-tycon type) class)))
  131.     (cond ((eq? instance '#f)
  132.        ;; This remove the instantiation which caused the type
  133.        ;; error - perhaps stop error propagation & make
  134.        ;; error message better.
  135.        (setf (ntyvar-value (dynamic *instantiated-tyvar*)) '#f)
  136.        (type-error "Type ~A is not in class ~A" type class))
  137.       (else
  138.        ;; The instance contains a list of class constraints for
  139.        ;; each argument.  This loop pairs the argument to the
  140.        ;; type constructor with the context required by the instance
  141.        ;; decl.
  142.        (dolist2 (classes (instance-gcontext instance))
  143.             (arg (ntycon-args type))
  144.          (propagate-contexts/inner arg classes))))))
  145.   'OK)
  146.  
  147. (define (propagate-dynamic-class type)
  148.   (dolist (arg (ntycon-args type))
  149.      (propagate-contexts/inner arg (list (core-symbol "DynamicType")))))
  150.  
  151. ;;; The routines which handle contexts (merge-contexts and context-implies?)
  152. ;;; are in type-utils.  The occurs check is also there.
  153.  
  154.  
  155.